#include <iostream>
#include <string>
#include <vector>
#include <cstdlib>

#include "addtest.h"
#include "projects.h"
#include "program.h"
#include "function.h"
#include "logint.h"
#include "antlradapter.h"
#include "util.h"

using namespace std;

extern string ProjectDirectoryPathGlobalVariable;

AddTest::AddTest(bool Is_GUI)
{
///Setup the object declared
IsGUI=Is_GUI;
CurrentState=ChooseFunction;
C_LR=new AntlrAdapter();
CurrentProgram=new Program(ProjectDirectoryPathGlobalVariable);
CurrentProgram->Process();
Print=CurrentProgram->GetFunctionNames();
Print+="Please chose the function you want to add a test for:\n";
}

AddTest::~AddTest()
{
delete C_LR;
if(DeleteProgram==true)
	delete CurrentProgram;
}

void AddTest::GoForward(string UserInput)
{
if(CurrentState==ChooseFunction)///State of chosing the function within the program to add Test Critian for
	{
	///Compare decision with the total total number of functions available in the program
	if(atoi(UserInput.c_str())>CurrentProgram->GetFunctionsCount())///If greater than max than error
		{
		LogInt InvalidUserInput('W',"Invalid function number","",IsGUI);
                InvalidUserInput.Display();
		}
	else///If less than max then chosen function is correct proceed to next state and get data
		{
		///Set data for next state 
		CurrentFunction=atoi(UserInput.c_str());
		Print=CurrentProgram->GetLinesOfFunctionAtPosition(atoi(UserInput.c_str()));
		Print+="Please type your test criteria as du<x,y> or exec<x,k> where x,y are line numbers and k=constant\n";
		///Proceed to next state
		CurrentState=ChooseCriteria;
		}
	}
else if(CurrentState==ChooseCriteria)//State of chosing the criteria for the current function
	{
	//TODO: Test if the criteria written is valid to (x before y) or (x atleast k)
	Criteria=UserInput;
	///Checking which type of criteria needed. Currently only def-use applicable and thus the first 2 letters need to be 'd' and 'u'
	if(UserInput[0]=='d' && UserInput[1]=='u')
		Criteria=DefUse();///Call the defuse function
	
	Print="Please choose the file that should invoke the chosen criteria\n";

	///Proceed to next State
	CurrentState=ChooseTest;
	}
else if(CurrentState==ChooseTest)//State is choosing the test file for the 
	{
	//TODO: check if the test path is correct
	Test=UserInput;
	CurrentState=ChooseFunction;
	Print=CurrentProgram->GetFunctionNames();
	Print+="Please choose the project you want to work on:\n";
	TestFile.push_back(Test);
	TestCriteria.push_back(Criteria);
	}
else /// Make sure we are in a state
	{	
		cout<<"failed to go in\n";
	}

if(IsGUI==false)
	{
	Print+="Press 'logout' to go to main menu\nPress 'back' to go back one step\n";
	}
}

void AddTest::GoBackward()
{
if(CurrentState==ChooseFunction)///Chosing Function, go backward => chose project
	{
	;
	}
else if(CurrentState==ChooseCriteria)///Chosing criteria, go backward => chose function
	{
	CurrentState=ChooseFunction;
	Print=CurrentProgram->GetFunctionNames();
	Print+="Please choose the function you want to work in:\n";
	}
else if(CurrentState==ChooseTest)///Chosing test, go backward => chose criteria
	{
	CurrentState=ChooseCriteria;
	Print=CurrentProgram->GetLinesOfFunctionAtPosition(CurrentFunction);
	Print+="Please type your test criteria as (x before y) or (x atleast k) where x,y are line numbers and k=constant\n";
	}
else
	{
		;//TODO:report error
	}

if(IsGUI==false)
        {
        Print+="Press 'logout' to go to main menu\nPress 'back' to go back one step\n";
        }

}

bool AddTest::IsValid()
{
if(CurrentState==Invalid)///Return false if in an invalid state
	return false;

return true;///Return true if in a valid state
}

string AddTest::GetPrint()
{
	return Print;///Get data to be printed on screen
}

string AddTest::DefUse()
{
///This is a defuse test criterion to be added
//Split the def and use into vector to get the line number of def and line number of use
vector<int> *DefUseLineNumber=(C_LR->TestCriteriaParameters(Criteria));

///Setup the specification of the def
string DefSpecification=CurrentProgram->GetFunctionNameAtPosition(CurrentFunction);///function name
DefSpecification+=".scope=";
DefSpecification+=ConvertIntToString(CurrentProgram->GetFunctionLineScopeAtPosition(CurrentFunction,DefUseLineNumber->at(0)));///line scope
DefSpecification+=".";
DefSpecification+=C_LR->Def(CurrentProgram->GetFunctionLineAtPosition(CurrentFunction,DefUseLineNumber->at(0)));///ANTLR specification

///Setup the specification of the user
string UseSpecification=CurrentProgram->GetFunctionNameAtPosition(CurrentFunction);///function name
UseSpecification+=".scope=";
UseSpecification+=ConvertIntToString(CurrentProgram->GetFunctionLineScopeAtPosition(CurrentFunction,DefUseLineNumber->at(1)));///line scope
UseSpecification+=".";
UseSpecification+=C_LR->Use(CurrentProgram->GetFunctionLineAtPosition(CurrentFunction,DefUseLineNumber->at(1)));///ANTLR specification

///Setup the line as a du<def_specification , use_specification>
string DUSpecification="du<";
DUSpecification+=DefSpecification;
DUSpecification+=" , ";
DUSpecification+=UseSpecification;
DUSpecification+=">";

return DUSpecification;
}

vector<string> AddTest::GetTestCriteria()
{
	return TestCriteria;
}

vector<string> AddTest::GetTestFile()
{
	return TestFile;
}
